package com.srmt.document.feishu.internal.table.impl.sheet;

import com.lark.oapi.service.docx.v1.model.*;
import com.srmt.document.exception.TableException;
import com.srmt.document.feishu.internal.table.model.TableContext;
import com.srmt.document.feishu.internal.table.util.SheetCoordinateHelper;
import com.srmt.document.model.ColumnData;
import com.srmt.document.model.RowData;
import com.srmt.feishu.client.FeishuClient;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 电子表格写入操作
 *
 * 封装所有与Sheet写入相关的操作，包括：
 * - 单元格内容更新
 * - 批量单元格更新
 * - 行操作（添加/删除）
 * - 列操作（添加/删除）
 *
 * @author srmt
 * @since 3.0.0
 */
public class SheetWriteOperations {

    private static final Logger logger = LoggerFactory.getLogger(SheetWriteOperations.class);

    private final FeishuClient client;
    private final SheetReadOperations readOps;

    public SheetWriteOperations(FeishuClient client, SheetReadOperations readOps) {
        if (client == null) {
            throw new IllegalArgumentException("客户端不能为null");
        }
        if (readOps == null) {
            throw new IllegalArgumentException("ReadOperations 不能为null");
        }
        this.client = client;
        this.readOps = readOps;
    }

    /**
     * 更新单个单元格内容
     *
     * @param context 表格上下文
     * @param row 行索引（1-based）
     * @param col 列索引（1-based）
     * @param value 单元格值
     * @throws TableException 操作失败时抛出
     */
    public void updateCellContentByIndex(TableContext context, int row, int col, String value)
            throws TableException {
        logger.debug("更新 sheet cell [{}, {}] with value: {}", row, col, value);

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();
        if (token == null || token.isEmpty()) {
            throw new TableException("电子表格令牌为空");
        }

        try {
            // 解析token
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts.length > 1 ? parts[1] : "";

            // 如果sheetId为空，获取默认sheet
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定工作表ID");
                }
            }

            // 构建A1表示法的范围
            String range = SheetCoordinateHelper.buildRange(sheetId, row, col, row, col);

            logger.debug("更新 cell at range: {} with value: {}", range, value);

            // 直接通过Sheets API更新
            List<List<String>> values = Arrays.asList(Arrays.asList(value != null ? value : ""));
            boolean success = client.sheets().updateValues(spreadsheetToken, range, values);

            if (!success) {
                throw new TableException("更新单元格值失败 via 电子表格s API");
            }

            logger.info("成功更新工作表中的单元格[{}, {}]", row, col);

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            logger.error("更新单元格内容失败: {}", e.getMessage());
            throw new TableException("更新单元格内容失败: " + e.getMessage());
        }
    }

    /**
     * 批量更新单元格内容
     *
     * @param context 表格上下文
     * @param cellUpdates 单元格更新映射（位置→值）
     * @throws TableException 操作失败时抛出
     */
    public void batchUpdateCellsByIndex(TableContext context, Map<int[], String> cellUpdates)
            throws TableException {
        if (cellUpdates == null || cellUpdates.isEmpty()) {
            return;
        }

        logger.debug("批量更新工作表中的{}个单元格", cellUpdates.size());

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();
        if (token == null || token.isEmpty()) {
            throw new TableException("电子表格令牌为空");
        }

        try {
            // 解析token
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts.length > 1 ? parts[1] : "";

            // 如果sheetId为空，获取默认sheet
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定工作表ID");
                }
            }

            // 构建批量更新的范围和值映射
            Map<String, List<List<String>>> rangeUpdates = new HashMap<>();

            for (Map.Entry<int[], String> entry : cellUpdates.entrySet()) {
                int[] position = entry.getKey();
                if (position == null || position.length < 2) {
                    logger.warn("无效的位置数组, skipping");
                    continue;
                }

                int row = position[0];
                int col = position[1];
                String value = entry.getValue();

                // 构建A1表示法的范围
                String range = SheetCoordinateHelper.buildRange(sheetId, row, col, row, col);

                // 创建单个单元格的值列表
                List<List<String>> values = Arrays.asList(Arrays.asList(value != null ? value : ""));
                rangeUpdates.put(range, values);
            }

            if (!rangeUpdates.isEmpty()) {
                logger.debug("执行{}个范围的批量更新", rangeUpdates.size());

                // 执行批量更新
                boolean success = client.sheets().batchUpdateValues(spreadsheetToken, rangeUpdates);

                if (!success) {
                    throw new TableException("执行批量更新失败");
                }

                logger.info("成功批量更新工作表中的{}个单元格", rangeUpdates.size());
            }

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            logger.error("批量更新单元格失败: {}", e.getMessage());
            throw new TableException("批量更新单元格失败: " + e.getMessage());
        }
    }

    /**
     * 添加表格行
     *
     * @param context 表格上下文
     * @param rows 要添加的行数据
     * @param position 插入位置（-1表示追加到末尾）
     * @throws TableException 操作失败时抛出
     */
    public void addTableRows(TableContext context, List<RowData> rows, int position)
            throws TableException {
        logger.debug("在位置{}向工作表添加{}行", position, rows.size());

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();

        try {
            // 解析token获取spreadsheetToken和sheetId
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts[1];

            // 如果sheetId为空，需要获取默认sheet的ID
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定电子表格的工作表ID: " + spreadsheetToken);
                }
            }

            // 获取当前表格维度
            int[] dimensions = readOps.getTableDimensions(context);
            int currentRowCount = dimensions[0];
            int columnCount = dimensions[1];

            // 计算插入位置
            int insertPosition;
            boolean isAppending = false;
            if (position < 0 || currentRowCount == 1) {
                // 追加到末尾
                insertPosition = currentRowCount;
                isAppending = true;
            } else {
                insertPosition = position;
                isAppending = false;
            }

            // Step 1: 插入或添加空白行
            if (rows.size() > 0) {
                boolean success = true;

                if (isAppending) {
                    // 如果是追加到末尾，使用 addDimensionRange
                    // 使用 client.sheets() 方法，已被限流和重试装饰器包装
                    logger.debug("在工作表末尾追加{}行(在第{}行之后)", rows.size(), currentRowCount);
                    success = client.sheets().addDimensionRange(
                        spreadsheetToken,
                        sheetId,
                        "ROWS",
                        rows.size()
                    );
                } else {
                    // 如果是在中间插入，使用 insertDimensionRange
                    // 使用 client.sheets() 方法，已被限流和重试装饰器包装
                    logger.debug("在位置{}插入{}行", insertPosition, rows.size());

                    for (int i = 0; i < rows.size(); i++) {
                        boolean singleInsert = client.sheets().insertDimensionRange(
                                spreadsheetToken,
                                sheetId,
                                "ROWS",
                                insertPosition,
                                insertPosition+1
                        );
                        if (!singleInsert) {
                            success = false;
                            break;
                        }
                    }
                }

                if (!success) {
                    throw new TableException((isAppending ? "追加" : "插入") + "工作表空白行失败");
                }

                logger.debug("成功{}{}个空白行在位置{}",
                           isAppending ? "appended" : "inserted", rows.size(), insertPosition);
            }

            // Step 2: 填充数据
            if (!rows.isEmpty() && rows.get(0).getCells() != null) {
                // 准备数据
                List<List<String>> values = new ArrayList<>();
                for (RowData row : rows) {
                    List<String> rowValues = new ArrayList<>();
                    if (row.getCells() != null) {
                        for (int i = 0; i < Math.min(row.getCells().size(), columnCount); i++) {
                            String cellValue = row.getCells().get(i);
                            rowValues.add(cellValue != null ? cellValue : "");
                        }
                        // 补齐列数
                        while (rowValues.size() < columnCount) {
                            rowValues.add("");
                        }
                    }
                    values.add(rowValues);
                }

                // 构建范围字符串 (使用A1表示法)
                String startCell = SheetCoordinateHelper.getCellReference(insertPosition, 0);
                String endCell = SheetCoordinateHelper.getCellReference(insertPosition + rows.size() - 1, columnCount - 1);
                String range = String.format("%s!%s:%s", sheetId, startCell, endCell);

                logger.debug("更新工作表范围: {}", range);

                // 更新数据（使用 client.sheets() 方法，已被限流和重试装饰器包装）
                boolean updateSuccess = client.sheets().updateValues(spreadsheetToken, range, values);

                if (!updateSuccess) {
                    logger.warn("更新工作表单元格值失败,但行已插入");
                } else {
                    logger.debug("成功更新工作表单元格值");
                }
            }

            logger.info("成功向工作表添加{}行", rows.size());

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            throw new TableException("向工作表添加行失败: " + e.getMessage());
        }
    }

    /**
     * 删除表格行
     *
     * @param context 表格上下文
     * @param startRow 起始行索引
     * @param endRow 结束行索引
     * @throws TableException 操作失败时抛出
     */
    public void deleteTableRows(TableContext context, int startRow, int endRow)
            throws TableException {
        logger.debug("删除 rows {} to {} from sheet", startRow, endRow);

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();
        if (token == null || token.isEmpty()) {
            throw new TableException("电子表格令牌为空");
        }

        try {
            // 解析token获取spreadsheetToken和sheetId
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts[1];

            // 如果sheetId为空，需要获取默认sheet的ID
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定电子表格的工作表ID: " + spreadsheetToken);
                }
            }

            // 删除行
            // 使用 client.sheets() 方法，已被限流和重试装饰器包装
            int apiStartIndex = startRow;
            int apiEndIndex = endRow;

            logger.debug("删除第{}行到第{}行(API索引: {}到{})",
                       startRow, endRow, apiStartIndex, apiEndIndex);

            boolean success = client.sheets().deleteDimensionRange(
                spreadsheetToken, sheetId, "ROWS", apiStartIndex, apiEndIndex
            );

            if (!success) {
                throw new TableException("删除工作表行失败");
            }

            logger.info("成功从工作表删除第{}行到第{}行", startRow, endRow);

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            throw new TableException("从工作表删除行失败: " + e.getMessage());
        }
    }

    /**
     * 添加表格列
     *
     * @param context 表格上下文
     * @param columns 要添加的列数据
     * @param position 插入位置（-1表示追加到末尾）
     * @throws TableException 操作失败时抛出
     */
    public void addTableColumns(TableContext context, List<ColumnData> columns, int position)
            throws TableException {
        if (columns == null || columns.isEmpty()) {
            logger.debug("没有需要添加的列");
            return;
        }

        logger.debug("在位置{}向工作表添加{}列", position, columns.size());

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();
        if (token == null || token.isEmpty()) {
            throw new TableException("电子表格令牌为空");
        }

        try {
            // 解析token获取spreadsheetToken和sheetId
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts[1];

            // 如果sheetId为空，需要获取默认sheet的ID
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定电子表格的工作表ID: " + spreadsheetToken);
                }
            }

            // 获取当前表格维度
            int[] dimensions = readOps.getTableDimensions(context);
            int rowCount = dimensions[0];
            int columnCount = dimensions[1];

            // 逐列插入
            // 使用 client.sheets() 方法，已被限流和重试装饰器包装
            for (int i = 0; i < columns.size(); i++) {
                ColumnData columnData = columns.get(i);

                // 计算插入位置
                int insertPosition;
                boolean isAppending = false;
                if (position < 0) {
                    // 追加到末尾
                    insertPosition = columnCount + i;
                    isAppending = true;
                } else {
                    insertPosition = position + i;
                    isAppending = false;
                }

                // Step 1: 插入或添加空白列
                boolean success;

                if (isAppending) {
                    logger.debug("在工作表末尾追加1列(在第{}列之后)", columnCount + i);
                    success = client.sheets().addDimensionRange(
                        spreadsheetToken,
                        sheetId,
                        "COLUMNS",
                        1
                    );
                } else {
                    logger.debug("在位置{}插入1列", insertPosition);
                    success = client.sheets().insertDimensionRange(
                        spreadsheetToken,
                        sheetId,
                        "COLUMNS",
                        insertPosition,
                        insertPosition + 1
                    );
                }

                if (!success) {
                    throw new TableException((isAppending ? "追加" : "插入") + "工作表列失败");
                }

                logger.debug("成功 {} column at position {}",
                           isAppending ? "appended" : "inserted", insertPosition);

                // Step 2: 填充列数据（如果提供了数据）
                if (columnData.getCells() != null && !columnData.getCells().isEmpty()) {
                    // 准备数据 - 每个元素作为一行
                    List<List<String>> values = new ArrayList<>();
                    for (int j = 0; j < Math.min(columnData.getCells().size(), rowCount); j++) {
                        List<String> rowValue = Arrays.asList(columnData.getCells().get(j));
                        values.add(rowValue);
                    }

                    // 构建范围字符串 (使用A1表示法)
                    String colLetter = SheetCoordinateHelper.getColumnLetter(isAppending ? (columnCount + i) : (position + i + 1));
                    String range = String.format("%s!%s1:%s%d", sheetId, colLetter, colLetter,
                                               Math.min(columnData.getCells().size(), rowCount));

                    logger.debug("更新范围{}的列数据", range);

                    // 更新数据（使用 client.sheets() 方法，已被限流和重试装饰器包装）
                    boolean updateSuccess = client.sheets().updateValues(spreadsheetToken, range, values);

                    if (!updateSuccess) {
                        logger.warn("更新工作表列数据失败,但列已插入");
                    } else {
                        logger.debug("成功更新工作表列数据");
                    }
                }
            }

            logger.info("成功向工作表添加{}列", columns.size());

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            throw new TableException("向工作表添加列失败: " + e.getMessage());
        }
    }

    /**
     * 删除表格列
     *
     * @param context 表格上下文
     * @param startCol 起始列索引
     * @param endCol 结束列索引
     * @throws TableException 操作失败时抛出
     */
    public void deleteTableColumns(TableContext context, int startCol, int endCol)
            throws TableException {
        logger.debug("删除 columns {} to {} from sheet", startCol, endCol);

        Block tableBlock = context.getTableBlock();
        if (tableBlock.getSheet() == null) {
            throw new TableException("块中未找到电子表格信息");
        }

        String token = tableBlock.getSheet().getToken();
        if (token == null || token.isEmpty()) {
            throw new TableException("电子表格令牌为空");
        }

        try {
            // 解析token获取spreadsheetToken和sheetId
            String[] parts = SheetCoordinateHelper.parseSheetToken(token);
            String spreadsheetToken = parts[0];
            String sheetId = parts[1];

            // 如果sheetId为空，需要获取默认sheet的ID
            if (sheetId.isEmpty()) {
                // querySheets现在直接返回Sheet[]，失败时抛出FeishuApiException
                com.lark.oapi.service.sheets.v3.model.Sheet[] sheets =
                    client.sheets().querySheets(spreadsheetToken);

                if (sheets != null && sheets.length > 0) {
                    sheetId = sheets[0].getSheetId();
                } else {
                    throw new TableException("无法确定电子表格的工作表ID: " + spreadsheetToken);
                }
            }

            // 删除列
            // 使用 client.sheets() 方法，已被限流和重试装饰器包装
            int apiStartIndex = startCol;
            int apiEndIndex = endCol;

            logger.debug("删除第{}列到第{}列(API索引: {}到{})",
                       startCol, endCol, apiStartIndex, apiEndIndex);

            boolean success = client.sheets().deleteDimensionRange(
                spreadsheetToken, sheetId, "COLUMNS", apiStartIndex, apiEndIndex
            );

            if (!success) {
                throw new TableException("删除工作表列失败");
            }

            logger.info("成功从工作表删除第{}列到第{}列", startCol, endCol);

        } catch (TableException e) {
            throw e;
        } catch (Exception e) {
            throw new TableException("从工作表删除列失败: " + e.getMessage());
        }
    }
}
